package pokerTests;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import exception.PlayerActionEx;
import exception.PlayerCountEx;
import poker.*;

public class TableGameLogicTest {

	Table theTable;
	Player[] playas;
	
	@Before
	public void init() throws Exception {
		playas = new Player[4];
		playas[0] = new Human("Zbysiek1", 100);
		playas[1] = new Human("Zbysiek2", 100);
		playas[2] = new Human("Zbysiek3", 100);
		playas[3] = new Human("Zbysiek4", 100);
		
		for(int i=0; i<5; i++) {
			for(int j=0; j<4; j++) {
				playas[j].receiveCard((short)(i*i));
			}
		}
		
		theTable = new Table(playas, 10);
	}
	
	@Test
	public void table_normalGame_expectNoExceptions() throws Exception {
		theTable.advance(PlayerAction.CHECK, 0);
		theTable.advance(PlayerAction.BET, 0);
		theTable.advance(PlayerAction.CALL, 0);
		theTable.advance(PlayerAction.RAISE, 15);
		theTable.advance(PlayerAction.FOLD, 0);
		theTable.advance(PlayerAction.CALL, 0);
		theTable.advance(PlayerAction.CALL, 0);
		
		int[] zeroTable = new int[5];
		theTable.advance(zeroTable);
		theTable.advance(zeroTable);
		theTable.advance(zeroTable);
		
		theTable.advance(PlayerAction.CALL, 0);
		theTable.advance(PlayerAction.RAISE, 30);
		theTable.advance(PlayerAction.CALL, 0);
		theTable.advance(PlayerAction.RAISE, 50);
		theTable.advance(PlayerAction.FOLD, 0);
		theTable.advance(PlayerAction.CALL, 0);
		assertEquals(Phase.AnnounceWinner, theTable.getPhase());
	}
	
	@Test
	public void table_disconnectTooMany_expectAnnounceWinnersPhase() throws Exception {
		theTable.disconnectPlayer(1);
		theTable.disconnectPlayer(2);
		theTable.disconnectPlayer(3);
		assertEquals(Phase.AnnounceWinner, theTable.getPhase());
	}
	
	@Test
	public void table_tooManyFolded_expectAnnounceWinnersPhase() throws Exception {
		theTable.advance(PlayerAction.FOLD, 0);
		theTable.advance(PlayerAction.FOLD, 0);
		theTable.advance(PlayerAction.FOLD, 0);
		assertEquals(Phase.AnnounceWinner, theTable.getPhase());
	}
	
	@Test
	public void table_playerDisconnected_expectThreePlayersNextGame() throws Exception {
		theTable.disconnectPlayer(4);
		theTable.advance(PlayerAction.BET, 0);
		theTable.advance(PlayerAction.CALL, 0);
		theTable.advance(PlayerAction.CALL, 0);

		int table[] = new int[5];
		theTable.advance(table);
		theTable.advance(table);
		theTable.advance(table);
		
		theTable.advance(PlayerAction.CALL, 0);
		theTable.advance(PlayerAction.CALL, 0);
		theTable.advance(PlayerAction.CALL, 0);
		
		theTable.disconnectPlayer(4);
		theTable.showResult();
		theTable.prepareNextGame();
		assertEquals(3, theTable.getPlayerCount());
	}

	@Test(expected = PlayerCountEx.class)
	public void table_playersBankrupt_ExpectNoNewGame() throws Exception {
		playas[0].dropHand();
		for(int i=0; i<5; i++) {
			playas[0].receiveCard((short)i);
		}
		for(int i=1; i<4; i++) {
			playas[i].pay(99);
		}
		theTable.advance(PlayerAction.BET, 0);
		theTable.advance(PlayerAction.ALLIN, 0);
		theTable.advance(PlayerAction.ALLIN, 0);
		theTable.advance(PlayerAction.ALLIN, 0);
		
		int[] zeroTable = new int[5];
		theTable.advance(zeroTable);
		theTable.advance(zeroTable);
		theTable.advance(zeroTable);
		theTable.advance(zeroTable);
		
		theTable.showResult();
		theTable.prepareNextGame();
	}
	
	@Test
	public void table_invalidActions_expectProperExceptions() throws Exception {
		try {
			theTable.advance(PlayerAction.CALL, 0);
			fail("Oczekiwano PlayerActionEx");
		} catch (PlayerActionEx e) {
			assertEquals("Nie ma stawki", e.getMessage());
		}
		try {
			theTable.advance(PlayerAction.ALLIN, 0);
			fail("Oczekiwano PlayerActionEx");
		} catch (PlayerActionEx e) {
			assertEquals("Nie ma stawki", e.getMessage());
		}
		try {
			theTable.advance(PlayerAction.RAISE, 0);
			fail("Oczekiwano PlayerActionEx");
		} catch (PlayerActionEx e) {
			assertEquals("Nie ma stawki", e.getMessage());
		}
		
		theTable.advance(PlayerAction.BET, 0);
		try {
			theTable.advance(PlayerAction.RAISE, 0);
			fail("Oczekiwano PlayerActionEx");
		} catch (PlayerActionEx e) {
			assertEquals("Za mało żeby przebić", e.getMessage());
		}
		try {
			theTable.advance(PlayerAction.RAISE, -1);
			fail("Oczekiwano PlayerActionEx");
		} catch (PlayerActionEx e) {
			assertEquals("Stawka ujemna", e.getMessage());
		}
		try {
			theTable.advance(PlayerAction.ALLIN, 0);
			fail("Oczekiwano PlayerActionEx");
		} catch (PlayerActionEx e) {
			assertEquals("Za dużo żetonów na all-in", e.getMessage());
		}
		try {
			theTable.advance(PlayerAction.BET, 0);
			fail("Oczekiwano PlayerActionEx");
		} catch (PlayerActionEx e) {
			assertEquals("Już jest stawka", e.getMessage());
		}
		try {
			theTable.advance(PlayerAction.CHECK, 0);
			fail("Oczekiwano PlayerActionEx");
		} catch (PlayerActionEx e) {
			assertEquals("Nie można czekać po stawce", e.getMessage());
		}
	}
}
